{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a128a7e5",
   "metadata": {},
   "source": [
    "# PyTorch 基础 : 张量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "16c577e8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2.0.1'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 首先要引入相关的包\n",
    "import torch\n",
    "import numpy as np\n",
    "#打印一下版本\n",
    "torch.__version__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab2c38e9",
   "metadata": {},
   "source": [
    "张量(Tensor)\n",
    "张量的英文是Tensor，它是PyTorch里面基础的运算单位，与Numpy的ndarray相同都表示的是一个多维的矩阵。 与ndarray的最大区别就是，PyTorch的Tensor可以在 GPU 上运行，而 numpy 的 ndarray 只能在 CPU 上运行，在GPU上运行大大加快了运算速度。\n",
    "\n",
    "下面我们生成一个简单的张量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ba3a6ff7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0.5951, 0.0703, 0.2495],\n",
       "        [0.7541, 0.2645, 0.2598]])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.rand(2, 3)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "e0ae6f33",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([2, 3])\n",
      "torch.Size([2, 3])\n"
     ]
    }
   ],
   "source": [
    "# 可以使用与numpy相同的shape属性查看\n",
    "print(x.shape)\n",
    "# 也可以使用size()函数，返回的结果都是相同的\n",
    "print(x.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3b69a98b",
   "metadata": {},
   "source": [
    "张量（Tensor）是一个定义在一些向量空间和一些对偶空间的笛卡儿积上的多重线性映射，其坐标是|n|维空间内，有|n|个分量的一种量， 其中每个分量都是坐标的函数， 而在坐标变换时，这些分量也依照某些规则作线性变换。r称为该张量的秩或阶（与矩阵的秩和阶均无关系）。 (来自百度百科)\n",
    "\n",
    "下面我们来生成一些多维的张量："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bb69de7b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([2, 3, 4, 5])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([[[[0.8925, 0.7688, 0.5376, 0.9090, 0.3460],\n",
       "          [0.1977, 0.6598, 0.1914, 0.1083, 0.8994],\n",
       "          [0.2098, 0.8425, 0.4468, 0.1764, 0.6948],\n",
       "          [0.1856, 0.6216, 0.1994, 0.0331, 0.2854]],\n",
       "\n",
       "         [[0.1961, 0.2323, 0.4606, 0.6976, 0.4448],\n",
       "          [0.0135, 0.4554, 0.4001, 0.7623, 0.3699],\n",
       "          [0.3770, 0.9851, 0.3178, 0.5614, 0.6758],\n",
       "          [0.9169, 0.2752, 0.6961, 0.5231, 0.7140]],\n",
       "\n",
       "         [[0.9208, 0.3172, 0.5569, 0.3195, 0.9812],\n",
       "          [0.7067, 0.4772, 0.8459, 0.5736, 0.5452],\n",
       "          [0.1580, 0.6742, 0.2760, 0.2861, 0.9775],\n",
       "          [0.9298, 0.9049, 0.3788, 0.3864, 0.2054]]],\n",
       "\n",
       "\n",
       "        [[[0.7440, 0.9144, 0.0804, 0.3297, 0.0265],\n",
       "          [0.6845, 0.4362, 0.1588, 0.8447, 0.7775],\n",
       "          [0.4928, 0.5098, 0.9086, 0.0848, 0.9111],\n",
       "          [0.7500, 0.9874, 0.0014, 0.7978, 0.8225]],\n",
       "\n",
       "         [[0.9727, 0.4951, 0.4937, 0.9685, 0.4790],\n",
       "          [0.0306, 0.1400, 0.5793, 0.2115, 0.2600],\n",
       "          [0.1501, 0.0837, 0.0976, 0.3957, 0.9768],\n",
       "          [0.8975, 0.6192, 0.2500, 0.4823, 0.8438]],\n",
       "\n",
       "         [[0.7361, 0.4059, 0.7063, 0.0078, 0.5042],\n",
       "          [0.3665, 0.9546, 0.6971, 0.3148, 0.4741],\n",
       "          [0.9068, 0.2135, 0.2684, 0.4423, 0.8732],\n",
       "          [0.7490, 0.1218, 0.1658, 0.4558, 0.4669]]]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = torch.rand(2, 3, 4, 5)\n",
    "print(y.shape)\n",
    "y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "248c75d4",
   "metadata": {},
   "source": [
    "在同构的意义下，第零阶张量 （r = 0） 为标量 （Scalar），第一阶张量 （r = 1） 为向量 （Vector）， 第二阶张量 （r = 2） 则成为矩阵 （Matrix），第三阶以上的统称为多维张量。\n",
    "\n",
    "其中要特别注意的就是标量，我们先生成一个标量："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c7de5702",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(3.1400)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "torch.Size([])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#我们直接使用现有数字生成\n",
    "scalar =torch.tensor(3.14)\n",
    "print(scalar)\n",
    "#打印标量的大小\n",
    "scalar.size()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bbbe7a2e",
   "metadata": {},
   "source": [
    "对于标量，我们可以直接使用 .item() 从中取出其对应的python对象的数值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "f94eecb8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.140000104904175"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "scalar.item()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccef367b",
   "metadata": {},
   "source": [
    "特别的：如果张量中只有一个元素的tensor也可以调用tensor.item方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "0dd78020",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([3.1400])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "torch.Size([1])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tensor = torch.tensor([3.14])\n",
    "print(tensor)\n",
    "tensor.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "3eab05ac",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.140000104904175"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tensor.item()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "23c90773",
   "metadata": {},
   "source": [
    "基本类型\n",
    "Tensor的基本数据类型有五种：\n",
    "\n",
    "32位浮点型：torch.FloatTensor。 (默认)\n",
    "\n",
    "64位整型：torch.LongTensor。\n",
    "\n",
    "32位整型：torch.IntTensor。\n",
    "\n",
    "16位整型：torch.ShortTensor。\n",
    "\n",
    "64位浮点型：torch.DoubleTensor。\n",
    "\n",
    "除以上数字类型外，还有 byte和chart型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "fad2cf75",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([3])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "long = tensor.long()\n",
    "long"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "7eec8233",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([3.1406], dtype=torch.float16)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "half=tensor.half()\n",
    "half"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "b8182fb5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([3], dtype=torch.int32)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int_t=tensor.int()\n",
    "int_t"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "ece9fc56",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([3.1400])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "flo = tensor.float()\n",
    "flo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "f408e170",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([3], dtype=torch.int16)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "short = tensor.short()\n",
    "short"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "997def94",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([3], dtype=torch.int8)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ch = tensor.char()\n",
    "ch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "723c30e0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([3], dtype=torch.uint8)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bt = tensor.byte()\n",
    "bt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4785ba0",
   "metadata": {},
   "source": [
    "## Numpy转换\n",
    "使用numpy方法将Tensor转为ndarray"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "a8314111",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1.2238755 ,  0.06760193],\n",
       "       [ 1.5015876 ,  0.1243539 ],\n",
       "       [-0.28393936,  1.3735167 ]], dtype=float32)"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = torch.randn((3, 2))\n",
    "# tensor转化为numpy\n",
    "numpy_a = a.numpy()\n",
    "numpy_a"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e88f4121",
   "metadata": {},
   "source": [
    "numpy转化为Tensor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "065cf66c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[-1.2239,  0.0676],\n",
       "        [ 1.5016,  0.1244],\n",
       "        [-0.2839,  1.3735]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch_a = torch.from_numpy(numpy_a)\n",
    "torch_a"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4c090e6",
   "metadata": {},
   "source": [
    "*Tensor和numpy对象共享内存，所以他们之间的转换很快，而且几乎不会消耗什么资源。但这也意味着，如果其中一个变了，另外一个也会随之改变。*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6972ca22",
   "metadata": {},
   "source": [
    "## 设备间转换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "b9487e9b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'torch.FloatTensor'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cpu_a = torch.rand(4, 3)\n",
    "cpu_a.type()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "2cd36c87",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "mps\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'torch.mps.FloatTensor'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#使用torch.backends.mps.is_available()来确定是否有mps设备\n",
    "device = torch.device(\"mps\" if torch.backends.mps.is_available() else \"cpu\")\n",
    "print(device)\n",
    "#将tensor传送到设备\n",
    "gpu_b=cpu_a.to(device)\n",
    "gpu_b.type()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "c11c255c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cpu\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'torch.FloatTensor'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#使用torch.cuda.is_available()来确定是否有cuda设备\n",
    "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "print(device)\n",
    "#将tensor传送到设备\n",
    "gpu_b=cpu_a.to(device)\n",
    "gpu_b.type()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c186ca26",
   "metadata": {},
   "source": [
    "## 初始化\n",
    "Pytorch中有许多默认的初始化方法可以使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "b39ac39e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0.3884, 0.8237, 0.0156],\n",
       "        [0.0839, 0.9261, 0.8016],\n",
       "        [0.9084, 0.2120, 0.8482],\n",
       "        [0.0578, 0.3832, 0.3409],\n",
       "        [0.8651, 0.3167, 0.5983]])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用[0,1]均匀分布随机初始化二维数组\n",
    "rnd = torch.rand(5, 3)\n",
    "rnd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "7ab99dba",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[1., 1.],\n",
       "        [1., 1.]])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 初始化，使用1填充\n",
    "one = torch.ones(2, 2)\n",
    "one"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "8e5d7e47",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0., 0.],\n",
       "        [0., 0.]])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 初始化，使用0填充\n",
    "zero=torch.zeros(2,2)\n",
    "zero"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "e4af171e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[1., 0., 0., 0.],\n",
       "        [0., 1., 0., 0.],\n",
       "        [0., 0., 1., 0.],\n",
       "        [0., 0., 0., 1.]])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#初始化一个单位矩阵，即对角线为1 其他为0\n",
    "eye=torch.eye(4, 4)\n",
    "eye"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9753471d",
   "metadata": {},
   "source": [
    "## 常用方法\n",
    "PyTorch中对张量的操作api 和 NumPy 非常相似，如果熟悉 NumPy 中的操作，那么他们二者基本是一致的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "4aab3f31",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[-0.2671, -0.7210, -1.2809],\n",
      "        [-0.1998, -0.0997, -0.6272],\n",
      "        [ 0.2529,  0.7665, -1.5516]])\n"
     ]
    }
   ],
   "source": [
    "x = torch.randn(3, 3)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "bfec2735",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([-0.2671, -0.0997,  0.7665]) tensor([0, 1, 1])\n"
     ]
    }
   ],
   "source": [
    "# 沿着行取最大值\n",
    "max_value, max_idx = torch.max(x, dim=1)\n",
    "print(max_value, max_idx)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "6e0f2153",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([ 0.2529,  0.7665, -0.6272]) tensor([2, 2, 1])\n"
     ]
    }
   ],
   "source": [
    "# 沿着列取最大值\n",
    "max_value, max_idx = torch.max(x, dim=0)\n",
    "print(max_value, max_idx)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "5c2da630",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([-2.2690, -0.9268, -0.5322])\n"
     ]
    }
   ],
   "source": [
    "# 每行 x 求和\n",
    "sum_x = torch.sum(x, dim=1)\n",
    "print(sum_x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "ef577d1d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[ 0.4576, -0.8415, -0.4252],\n",
      "        [ 0.3438, -0.6132, -0.5906],\n",
      "        [-0.7987,  3.8382, -1.8315]])\n"
     ]
    }
   ],
   "source": [
    "y=torch.randn(3, 3)\n",
    "z = x + y\n",
    "print(z)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92eef656",
   "metadata": {},
   "source": [
    "以_为结尾的，均会改变调用值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "098f27b1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[ 0.4576, -0.8415, -0.4252],\n",
      "        [ 0.3438, -0.6132, -0.5906],\n",
      "        [-0.7987,  3.8382, -1.8315]])\n"
     ]
    }
   ],
   "source": [
    "# add 完成后x的值改变了\n",
    "x.add_(y)\n",
    "print(x)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "d2l",
   "language": "python",
   "name": "d2l"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
